﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
/*
 * 实现窗体最大化时不遮挡任务栏
 */
namespace Ezhu.WPFWin.Base
{
    internal class ScreenManager
    {
        private const int WM_GETMINMAXINFO = 0x0024;
        internal static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handle)
        {
            switch (msg)
            {
                case WM_GETMINMAXINFO:
                    WmGetMinMaxInfo(hwnd, lParam);
                    handle = true;
                    break;
                default:
                    break;
            }
            return (IntPtr)0;
        }

        private static void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
        {
            //将非托管代码转换为指定的类型文件并保存
            MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO));

            int Monitor_DefaultTonearest = 0x00000002;
            IntPtr monitor = MonitorFromWindow(hwnd, Monitor_DefaultTonearest);
            if (monitor != null && monitor != System.IntPtr.Zero)
            {
                MONITORINFO monitorInfo = new MONITORINFO();
                GetMonitorInfo(monitor, monitorInfo);
                RECT rcWorkArea = monitorInfo.rcWork;
                RECT rcMonitorArea = monitorInfo.rcMonitor;
                mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left);
                mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);
                mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left);
                mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
                mmi.ptMinTrackSize.x = 450;
                mmi.ptMinTrackSize.y = 380;
                mmi.ptMaxTrackSize.x = rcMonitorArea.Width;
                mmi.ptMaxTrackSize.y = rcMonitorArea.Height;
            }
            Marshal.StructureToPtr(mmi, lParam, true);
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MINMAXINFO
        {
            public POINT ptReserved;
            /// <summary>
            /// 主显示器的最大高（宽）度
            /// </summary>
            public POINT ptMaxSize;
            /// <summary>
            /// 显示的最大高宽度
            /// </summary>
            public POINT ptMaxPosition;
            /// <summary>
            /// 最小的高宽度，可用于限定的最小区域
            /// </summary>
            public POINT ptMinTrackSize;
            /// <summary>
            /// 最大的高宽度
            /// </summary>
            public POINT ptMaxTrackSize;
        }
        /// <summary>
        /// 定义点的x、y轴点，作为MinMaxInfo的属性类型
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int x;
            public int y;

            public POINT(int _x, int _y)
            {
                this.x = _x;
                this.y = _y;
            }
        }
        public struct RECT
        {
            public static readonly RECT Empty = new RECT();
            public int left;
            public int top;
            public int right;
            public int bottom;

            /// <summary> Win32窗口宽度 </summary>
            public int Width
            {
                get { return Math.Abs(right - left); }  // Abs needed for BIDI OS
            }
            /// <summary> Win32窗口高度 </summary>
            public int Height
            {
                get { return bottom - top; }
            }
            /// <summary> Win32窗口 </summary>
            public RECT(int left, int top, int right, int bottom)
            {
                this.left = left;
                this.top = top;
                this.right = right;
                this.bottom = bottom;
            }
            /// <summary> Win32窗口 </summary>
            public RECT(RECT rcSrc)
            {
                this.left = rcSrc.left;
                this.top = rcSrc.top;
                this.right = rcSrc.right;
                this.bottom = rcSrc.bottom;
            }
        }
        /// <summary>
        /// 该函数返回一个显示器的信息
        /// </summary>
        /// <param name="hMonitor">显示器的句柄</param>
        /// <param name="lpmi">显示器信息(输出参数)</param>
        /// <returns></returns>
        [DllImport("user32")]
        internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi);
        /// <summary>
        /// 包含显示器信息的类型
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public class MONITORINFO
        {
            /// <summary>
            /// 必须指定MONITORINFO结构中的cbSize,大小为 sizeof(MONITORINFO) 或者sizeof(MONITORINFOEX)
            /// </summary>
            public int cbSize = Marshal.SizeOf(typeof(MONITORINFO));

            /// <summary>
            /// 显示屏
            /// </summary>
            public RECT rcMonitor = new RECT();

            /// <summary>
            /// 可工作显示区
            /// </summary>
            public RECT rcWork = new RECT();

            public int dwFlags = 0;
        }
        /// <summary>
        /// 获取到屏幕上具有最大交集区域的边界矩形的一个指定的窗口句柄。（能处理多显示器的问题）
        /// </summary>
        /// <param name="handle">窗口句柄</param>
        /// <param name="flags">可能为null、最接近的窗口、主显示屏</param>
        /// <returns></returns>
        [DllImport("User32")]
        internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
    }
}
